package com.hjk.common.utils.reflect;

import com.hjk.common.utils.check.Check;
import com.hjk.common.utils.string.JsonUtils;
import com.hjk.common.utils.string.LogUtils;
import com.hjk.common.model.vo.UserAddDTO;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.Reflector;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 属性工具类
 *
 * @author 黄军凯
 * @date 2019/4/7
 */
public class FieldUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(FieldUtils.class);

    /**
     * 获取对象属性名
     *
     * @param o    对象
     * @param flag true获取非空的属性名,false获取空的属性名
     * @return 非空属性名集合 或 空属性名集合
     */
    public static String[] getField(Object o, Boolean flag) {
        List<String> list = new ArrayList<>();
        Class<?> aClass = o.getClass();
        Field[] fields = aClass.getDeclaredFields();

        Arrays.stream(fields).forEach(field -> {
            //属性名
            String fieldName = field.getName();
            //获取属性值
            String fieldValue = getFieldValue(o, fieldName);
            //判断属性值是否非空
            if (flag) {
                if (StringUtils.isNotBlank(fieldValue)) {
                    list.add(fieldName);
                }
            } else {
                if (StringUtils.isBlank(fieldValue)) {
                    list.add(fieldName);
                }
            }
        });
        return list.toArray(new String[0]);
    }

    /**
     * 获取对象属性值不为空的属性名
     *
     * @param o 对象
     * @return
     */
    public static String[] getFieldIsNotNull(Object o) {
        List<String> list = new ArrayList<>();
        Class<?> aClass = o.getClass();
        Field[] fields = aClass.getDeclaredFields();

        for (Field field : fields) {
            //属性名
            String fieldName = field.getName();
            if ("serialVersionUID".equals(fieldName)) {
                continue;
            }
            //获取属性值
            String fieldValue = getFieldValue(o, fieldName);
            //判断属性值是否非空
            if (StringUtils.isNotBlank(fieldValue)) {
                list.add(fieldName);
            }
        }
        return list.toArray(new String[0]);
    }

    /**
     * 获取对象属性值为空的属性名集合
     *
     * @param o 对象
     * @return
     */
    public static String[] getFieldIsNull(Object o) {
        List<String> list = new ArrayList<>();

        Class<?> aClass = o.getClass();
        Field[] fields = aClass.getDeclaredFields();

        for (Field field : fields) {
            //属性名
            String fieldName = field.getName();
            if ("serialVersionUID".equals(fieldName)) {
                continue;
            }
            //获取属性值
            String fieldValue = getFieldValue(o, fieldName);
            if (StringUtils.isBlank(fieldValue)) {
                list.add(fieldName);
            }
        }
        return list.toArray(new String[0]);
    }


    /**
     * 获取对象的属性值
     *
     * @param o         对象
     * @param fieldName 属性名
     * @return  get方法的值或者null
     */
    private static String getFieldValue(Object o, String fieldName) {
        Class<?> clz = o.getClass();
        try {
            Method method = clz.getMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));

            if (Check.objectNonNull(method)) {
                Object invoke = method.invoke(o);
                //如果不为空,则返回值
                if (Check.objectNonNull(invoke)) {
                    return invoke.toString();
                }
            }

        } catch (Exception e) {
            LOGGER.error("获取 {} 属性失败", o,e);
        }
        //为空返回null
        return null;
    }

    /**
     * 获取对象为静态java.lang.String的属性和值
     *
     * @return 集合
     */
    private static List<String> getStaticFields(Class<?> clz) {
        Check.checkObsIsNotNull(clz);
        Field[] fields = clz.getDeclaredFields();
        try {
            List<String> fieldList = new ArrayList<>();
            for (Field field : fields) {
                field.setAccessible(true);
                if (/*field.getType().toString().endsWith("java.lang.String") && */
                        Modifier.isStatic(field.getModifiers())) {
                    String format = LogUtils.format("{}={}", field.getName(), field.get(clz));
                   // System.out.println(format);
                    fieldList.add("\n"+format+"\n");
                }
            }
            return fieldList;
        } catch (Exception e) {
            LOGGER.error("获取对象的属性和值失败", e);
        }
        return null;
    }

    private static String getSignature(Method method) {
        StringBuilder sb = new StringBuilder();
        //获取方法返回类型
        Class<?> returnType = method.getReturnType();
        if (returnType != null) {
            sb.append(returnType.getName()).append('#');
        }
        //拼接方法名
        sb.append(method.getName());
        Class<?>[] parameters = method.getParameterTypes();
        for (int i = 0; i < parameters.length; i++) {
            sb.append(i == 0 ? ':' : ',').append(parameters[i].getName());
        }
        return sb.toString();
    }

    /**
     *
     */
    @Test
    public void test2() {
       // List<String> staticFields = FieldUtils.getStaticFields(DateConstant.class);
        //System.out.println(JsonUtils.jsonFormat(staticFields));;

        Reflector reflector = new DefaultReflectorFactory().findForClass(UserAddDTO.class);
        System.out.println(JsonUtils.jsonFormat(reflector));

        String[] names = reflector.getGetablePropertyNames();
        System.out.println(Arrays.toString(names));
        String[] fieldIsNull = FieldUtils.getFieldIsNull(names);
        System.out.println(Arrays.toString(fieldIsNull));
    }
    @Test
    @SneakyThrows
    public void test3(){
        Method method = FieldUtils.class.getMethod("getField", Object.class, Boolean.class);
        System.out.println(getSignature(method));
        Method root = method.getClass().getDeclaredMethod("getRoot");
        root.setAccessible(true);
        System.out.println(root.invoke(root));
    }
}
